/*****************************************************
 * 本文件函数用于记录标定参数，断电不丢失
 *****************************************************/

#include <xc.h>
#include "DataRecord.h"
//dsPIC33EP256GP50X, dsPIC33EP256MC20X/50X, PIC24EP256GP/MC20X这类256K的器件
//用户编程flash存储有88K个指令字空间，地址范围为:0x000200-0x02AFEA
//写锁存器占2个指令字，地址为：0xFA0000和0xFA0002
//USERID起始为0x800FF8，结束0x800FFE
//DEVID起始0xFF0000，结束0xFF0002


//定义存储数据所在空间的起始地址,0x02A000，结束地址为0x2AFE8，可存储数据量为:(0x2AFE8-0x2A000+2)/2=4074
#define DATA_RECORD_START_PAGE 0x0002
#define DATA_RECORD_START_ADDR 0xA000


//index要小于4074,目前开辟的最大的用于存储数量的空间索引为4073
//读取flash内容
uint16_t DataRecord_ReadData(uint16_t index)
{
    FlashAddr_t flashAddr;
    flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;
    flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+index*2;
    return InnerFlash_ReadInstructionLow(flashAddr);
}

void DataRecord_ErasePage()
{
    FlashAddr_t flashAddr;
    flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;
    flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR;
    InnerFlash_EraseFlashPage(flashAddr);
}

//可写范围为0x2A000-0x2AF7E，总共一页，长度为0x800，每2个地址一个指令字，总共1024个指令字
//往flash写入内容
uint16_t DataRecord_WriteData(uint16_t index, volatile OneInstruction_t data)
{
    if(index>1023)  //超过一页
        return 0xa5a5;
    
    FlashAddr_t flashAddr;
    flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;
    flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+index*2;
    //读取对应地址数据，若数据与要写入的一致，则不再写入
    OneInstruction_t dataTmp = InnerFlash_ReadOneInstruction(flashAddr);
    if(dataTmp.UINT32==data.UINT32) //写入与实际的一样，不用写入
        return 0xffff;
    
    //先读取一页，再擦除，修改读取数据，写入一页
    OneInstruction_t pageData[1024];
    uint16_t i;
    
    //先将对应页的数据全部读出来，0x800个地址，0x400个字
    for(i=0;i<1024;i++)
    {
        flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+i*2;
        pageData[i] = InnerFlash_ReadOneInstruction(flashAddr);
    }
    
    
    //擦除整页
    flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR;
    InnerFlash_EraseFlashPage(flashAddr);
    
    //修改数据，每1024个数据pageData索引要从0重新开始
    pageData[index] = data;
    
    //将修改后的数据写回该页
    InnerFlash_WriteInstructionsToFlash(flashAddr,pageData,1024);

    return 0;
}

//不允许数组超过一页
uint16_t DataRecord_WriteDataArray(uint16_t index, volatile OneInstruction_t *data, uint16_t length)
{
    //超过一页
    if((index+length)>1023)
        return 0xa5a5;
    
    FlashAddr_t flashAddr;
    uint16_t i,cmpNZ=0;
    OneInstruction_t pageData[1024];
    
    //取对应页的首地址
    flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;
    flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+index*2;
    
    
    //比对数组
    for(i=index;i<length;i++)
    {
        //读取对应地址数据，若数据与要写入的一致，则不再写入
        flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+i*2;
        pageData[i] = InnerFlash_ReadOneInstruction(flashAddr);
        if(pageData[i].UINT32!=data[i-index].UINT32) //只要有一个数据不同，则需要重新写入
        {
            cmpNZ = 1;
            break;
        }
    }
    
    if(cmpNZ==0) //数据完全一致，不写入
        return 0xffff;
    
    
    //先读取一页，再擦除，修改读取数据，写入一页
    for(i=0;i<1024;i++)
    {
        //读取对应地址数据，若数据与要写入的一致，则不再写入
        flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+i*2;
        pageData[i] = InnerFlash_ReadOneInstruction(flashAddr);
    }
    
    flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR;
    //擦除整页
    InnerFlash_EraseFlashPage(flashAddr);
    
    for(i=index;i<length;i++)
    {
        //修改数据，每1024个数据pageData索引要从0重新开始
        pageData[index-(index/1024)*1024+i].UINT32 = data[i].UINT32;
    }
    
    //将修改后的数据写回该页
    InnerFlash_WriteInstructionsToFlash(flashAddr,pageData,1024);

    return 0;
}


//擦除一大页flash
void EraseLargePage(uint16_t pageIndex)
{
    uint16_t offset;
    FlashAddr_t flashAddr;
    flashAddr.Uint16Addr.HighAddr = pageIndex;
    switch(pageIndex)
    {
        case 0:
            //擦除外设配置
            flashAddr.Uint16Addr.LowAddr = 0;
            InnerFlash_EraseFlashPage(flashAddr);
            //第零大页
            for(offset=0x8000;offset<=0xF800;offset+=0x800)
            {
                flashAddr.Uint16Addr.LowAddr = offset;
                InnerFlash_EraseFlashPage(flashAddr);
                if(offset>=0xF800)
                    break;
            }
            break;
    
        case 1:
        //第一大页
        for(offset=0;offset<=0xF800;offset+=0x800)
        {
            flashAddr.Uint16Addr.LowAddr = offset;
            InnerFlash_EraseFlashPage(flashAddr);
            if(offset>=0xF800)
                break;
        }
        break;
        case 2:
        //第二大页
        for(offset=0;offset<0xA800;offset+=0x800)
        {
            flashAddr.Uint16Addr.LowAddr = offset;
            InnerFlash_EraseFlashPage(flashAddr);
        }
        break;
        default:break;
    }
}

//填充一大页flash
void FillLagrePage(uint16_t pageIndex)
{
    volatile uint16_t offset=0;
    volatile FlashAddr_t source_addr;
    volatile OneInstruction_t data[2];
    
    switch(pageIndex)
    {
        case 0:
            for(offset=0x8000;offset<=0xFFFC;offset+=4)
            {
                source_addr.Uint16Addr.HighAddr = 0;
                source_addr.Uint16Addr.LowAddr = offset;
                data[0].HighLowUINT16s.HighWord = 0xF0;
                data[0].HighLowUINT16s.LowWord = offset;
                data[1].HighLowUINT16s.HighWord = 0xF0;
                data[1].HighLowUINT16s.LowWord = offset+2;
                InnerFlash_WriteInstructionsToFlash(source_addr,data,2);
                //由于最大值为0xFFFF，超过会从0开始，0xFFFC+4=0x0000;
                if(offset>=0xFFFC)
                    break; //跳出循环
            }
    
            break;
        case 1:
            
            for(offset=0;offset<=0xFFFC;offset+=4)
            {
                source_addr.Uint16Addr.HighAddr = 1;
                source_addr.Uint16Addr.LowAddr = offset;
                data[0].HighLowUINT16s.HighWord = 0xF1;
                data[0].HighLowUINT16s.LowWord = offset;
                data[1].HighLowUINT16s.HighWord = 0xF1;
                data[1].HighLowUINT16s.LowWord = offset+2;
                InnerFlash_WriteInstructionsToFlash(source_addr,data,2);
                //由于最大值为0xFFFF，超过会从0开始，0xFFFC+4=0x0000;
                if(offset>=0xFFFC)
                    break; //跳出循环
            }
    
    
            break;
        case 2:
            //InnerFlash_EraseFlashPage(2,0xA800);
            for(offset=0;offset<0xA800;offset+=4)
            {
                source_addr.Uint16Addr.HighAddr = 2;
                source_addr.Uint16Addr.LowAddr = offset;
                data[0].HighLowUINT16s.HighWord = 0xF2;
                data[0].HighLowUINT16s.LowWord = offset;
                data[1].HighLowUINT16s.HighWord = 0xF2;
                data[1].HighLowUINT16s.LowWord = offset+2;
                InnerFlash_WriteInstructionsToFlash(source_addr,data,2);
            }
            break;


        default:break;
    }
}